//-----------------------------------------------------------------------
// <copyright file="OrderedCallsAcceptanceTest.cs" company="NMock2">
//
//   http://www.sourceforge.net/projects/NMock2
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
// </copyright>
// This is the easiest way to ignore StyleCop rules on this file, even if we shouldn't use this tag:
// <auto-generated />
//-----------------------------------------------------------------------
namespace NMock2.AcceptanceTests
{
    using System.Collections;
    using System.IO;
    using NMock2.Internal;
    using NMock2.Monitoring;
    using NUnit.Framework;

    [TestFixture]
    public class OrderedCallsAcceptanceTest : AcceptanceTestBase
    {
        private IHelloWorld helloWorld;
        
        [SetUp]
        public void SetUp()
        {
            base.Setup();

            helloWorld = (IHelloWorld)Mocks.NewMock(typeof(IHelloWorld));
        }
        
        [Test]
        public void DoesNotEnforceTheOrderOfCallsByDefault()
        {
            Expect.Once.On(helloWorld).Method("Hello");
            Expect.Once.On(helloWorld).Method("Goodbye");

            helloWorld.Goodbye();
            helloWorld.Hello();
        }
        
        [Test]
        public void UnorderedExpectationsMatchInOrderOfSpecification()
        {
            Expect.Once.On(helloWorld).Method("Ask").With(NMock2.Is.Anything).Will(Return.Value("1"));
            Expect.Once.On(helloWorld).Method("Ask").With(NMock2.Is.Anything).Will(Return.Value("2"));

            Assert.AreEqual("1", helloWorld.Ask("ignored"), "first call");
            Assert.AreEqual("2", helloWorld.Ask("ignored"), "second call");
        }

        [Test, ExpectedException(typeof(ExpectationException))]
        public void EnforcesTheOrderOfCallsWithinAnInOrderBlock()
        {
            SkipVerificationForThisTest();
            
            using(Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                Expect.Once.On(helloWorld).Method("Goodbye");
            }
            
            helloWorld.Goodbye();
            helloWorld.Hello();
        }
        
        [Test]
        public void AllowsCallsIfCalledInSameOrderAsExpectedWithinAnInOrderBlock()
        {
            using(Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                Expect.Once.On(helloWorld).Method("Goodbye");
            }
            
            helloWorld.Hello();
            helloWorld.Goodbye();
        }
        
        [Test]
        public void CanExpectUnorderedCallsWithinAnOrderedSequence()
        {
            using(Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                using (Mocks.Unordered)
                {
                    Expect.Once.On(helloWorld).Method("Umm");
                    Expect.Once.On(helloWorld).Method("Err");
                }
                Expect.Once.On(helloWorld).Method("Goodbye");
            }

            helloWorld.Hello();
            helloWorld.Err();
            helloWorld.Umm();
            helloWorld.Goodbye();
        }

        [Test, ExpectedException(typeof(ExpectationException))]
        public void UnorderedCallsWithinAnInOrderedBlockCannotBeCalledBeforeTheStartOfTheUnorderedExpectations()
        {
            SkipVerificationForThisTest();
            
            using (Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                using(Mocks.Unordered)
                {
                    Expect.Once.On(helloWorld).Method("Umm");
                    Expect.Once.On(helloWorld).Method("Err");
                }
                Expect.Once.On(helloWorld).Method("Goodbye");
            }

            helloWorld.Err();
            helloWorld.Hello();
            helloWorld.Umm();
            helloWorld.Goodbye();
        }

        [Test, ExpectedException(typeof(ExpectationException))]
        public void UnorderedCallsWithinAnInOrderedBlockCannotBeCalledAfterTheEndOfTheUnorderedExpectations()
        {
            SkipVerificationForThisTest();
            
            using(Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                using(Mocks.Unordered)
                {
                    Expect.Once.On(helloWorld).Method("Umm");
                    Expect.Once.On(helloWorld).Method("Err");
                }
                Expect.Once.On(helloWorld).Method("Goodbye");
            }

            helloWorld.Hello();
            helloWorld.Err();
            helloWorld.Goodbye();
            helloWorld.Umm();
        }
        
        [Test]
        public void CallsWithinAnInOrderedBlockCanBeExpectedMoreThanOnce()
        {
            using (Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                Expect.AtLeastOnce.On(helloWorld).Method("Err");
                Expect.Once.On(helloWorld).Method("Goodbye");
            }
            
            helloWorld.Hello();
            helloWorld.Err();
            helloWorld.Err();
            helloWorld.Goodbye();
        }
        
        [Test]
        [ExpectedException(typeof(ExpectationException))]
        public void CallsInOrderedBlocksThatAreNotMatchedFailVerification()
        {
            SkipVerificationForThisTest();
            
            using(Mocks.Ordered)
            {
                Expect.Once.On(helloWorld).Method("Hello");
                Expect.Once.On(helloWorld).Method("Goodbye");
            }
            
            helloWorld.Hello();

            Mocks.VerifyAllExpectationsHaveBeenMet();
        }
    }
}
